package com.mdd.admin.service.bill.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.response.AlipayTradeOrderSettleResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mdd.admin.service.IUserService;
import com.mdd.admin.service.bill.IOrderBillPayService;
import com.mdd.admin.service.bill.OrderBillInfoService;
import com.mdd.admin.service.order.IOrderInfoService;
import com.mdd.admin.service.royalty.AlipayRoyaltyAccountInfoService;
import com.mdd.admin.service.settle.AlipayTradeOrderRoyaltyDetailInfoService;
import com.mdd.admin.service.settle.AlipayTradeOrderSettleService;
import com.mdd.admin.service.sign.AlipaySignUserAgreementRecordService;
import com.mdd.admin.service.trade.AlipayTradePayInfoService;
import com.mdd.admin.tools.OrderNoUtils;
import com.mdd.admin.validate.bill.AuditOrderBillValidate;
import com.mdd.admin.validate.bill.OrderBillInfoValidate;
import com.mdd.admin.vo.user.UserVo;
import com.mdd.common.entity.*;
import com.mdd.common.entity.agreement.AlipaySignUserAgreementRecord;
import com.mdd.common.entity.order.OrderClue;
import com.mdd.common.entity.order.OrderInfo;
import com.mdd.common.enums.order.status.LeaseOrderStatusEnum;
import com.mdd.common.enums.order.type.OrderFlowTypeEnum;
import com.mdd.common.enums.pay.TradePayStatusEnum;
import com.mdd.common.enums.settle.OrderSettleStatusEnum;
import com.mdd.common.mapper.OrderFlowInfoMapper;
import com.mdd.common.mapper.order.OrderClueMapper;
import com.mdd.common.util.CodeUtils;
import com.mdd.enums.TransInType;
import com.mdd.service.divide.DivideAccountService;
import com.mdd.service.pay.AlipayAuthTradeService;
import com.mdd.system.api.ConfigApi;
import com.mdd.system.service.ISystemAuthDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 账单支付类
 * @author LikeAdmin
 */
@Slf4j
@Service
public class OrderBillPayServiceImpl implements IOrderBillPayService {
    @Resource
    AlipayAuthTradeService alipayAuthTradeService;
    @Resource
    AlipayRoyaltyAccountInfoService alipayRoyaltyAccountInfoService;
    @Resource
    AlipayTradeOrderSettleService alipayTradeOrderSettleService;
    @Resource
    DivideAccountService divideAccountService;
    @Resource
    AlipayTradeOrderRoyaltyDetailInfoService alipayTradeOrderRoyaltyDetailInfoService;
    @Resource
    DefaultAlipayClient defaultAlipayClient;
    @Resource
    AlipaySignUserAgreementRecordService alipaySignUserAgreementRecordService;
    @Resource
    AlipayTradePayInfoService alipayTradePayInfoService;
    @Resource
    OrderFlowInfoMapper orderFlowInfoMapper;
    @Resource
    OrderBillInfoService orderBillInfoService;
    @Resource
    IOrderInfoService iOrderInfoService;
    @Resource
    ISystemAuthDeptService iSystemAuthDeptService;
    @Resource
    IUserService iUserService;
    @Resource
    OrderClueMapper orderClueMapper;
    @Resource
    ConfigApi configApi;
    @Transactional
    @Override
    public void execOrderBill(OrderBillInfo orderBillInfo){
        AlipayTradePayModel tradePayModel = new AlipayTradePayModel();
        AlipaySignUserAgreementRecord agreementRecord = alipaySignUserAgreementRecordService.getRecordByUserId(orderBillInfo.getUserId());
        AgreementParams agreementParams = new AgreementParams();
        agreementParams.setAgreementNo(agreementRecord.getAgreementNo());
        //代扣信息。 代扣业务需要传入的协议相关信息，使用本参数传入协议号后scene和auth_code不需要再传值。
        tradePayModel.setAgreementParams(agreementParams);
        //商户订单号
        tradePayModel.setOutTradeNo(OrderNoUtils.getOrderUUID("otn" + orderBillInfo.getOrderId().toString()));
        long betweenDay = DateUtil.between(DateUtil.calendar().getTime(), orderBillInfo.getRepaymentEndDate(), DateUnit.DAY);
        BigDecimal dayPaidInAmount;
        if (betweenDay == 0 || betweenDay < 0) {
            //今天为该账单还款账单的最后一天，发起扣款为待缴纳全部金额
            //逾期账单
            dayPaidInAmount = orderBillInfo.getTotalReceivables().subtract(orderBillInfo.getTotalPaidInAmount());
            orderBillInfo.setStatus(LeaseOrderStatusEnum.PAID.getCode());
            orderBillInfo.setTotalPaidInAmount(orderBillInfo.getTotalPaidInAmount().add(dayPaidInAmount));
        } else {
            long days = DateUtil.between(orderBillInfo.getRepaymentStartDate(), orderBillInfo.getRepaymentEndDate(), DateUnit.DAY);
            //未逾期账单
            dayPaidInAmount = orderBillInfo.getTotalReceivables().divide(new BigDecimal(days), 2, RoundingMode.HALF_DOWN);
            orderBillInfo.setTotalPaidInAmount(orderBillInfo.getTotalPaidInAmount().add(dayPaidInAmount));
        }
        //设置交易金额（代扣）
        tradePayModel.setTotalAmount(dayPaidInAmount.toString());
        //支出方账户信息
        AlipayRoyaltyAccountInfo seller = alipayRoyaltyAccountInfoService.getSysAccountByOrganizationType();
        AlipayRoyaltyAccountInfo outAccountInfo = alipayRoyaltyAccountInfoService.getAccountByMerchantId(orderBillInfo.getMerchantId());
        if(Objects.isNull(outAccountInfo)){
            outAccountInfo = alipayRoyaltyAccountInfoService.getAccountByMerchantId(1L);
        }
        //设置订单名称
        tradePayModel.setSubject(orderBillInfo.getName());
        tradePayModel.setProductCode("GENERAL_WITHHOLDING");
        //设置卖家编号
        tradePayModel.setSellerId(seller.getAccount());

        //二级商户 default_settle_rule
        SubMerchant subMerchant = new SubMerchant();
        subMerchant.setMerchantId(outAccountInfo.getAccount());
        tradePayModel.setSubMerchant(subMerchant);
        tradePayModel.setOutTradeNo(OrderNoUtils.getOrderUUID("otn" + orderBillInfo.getOrderId().toString()));
        //结算信息
        SettleInfo settleInfo = new SettleInfo();
        SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
        settleDetailInfo.setAmount(tradePayModel.getTotalAmount());
        settleDetailInfo.setTransInType("defaultSettle");
        List<SettleDetailInfo> settleDetailInfoList = new ArrayList<>();
        settleDetailInfoList.add(settleDetailInfo);
        settleInfo.setSettleDetailInfos(settleDetailInfoList);
        tradePayModel.setSettleInfo(settleInfo);
        try {
            log.info("tradePay------>" + JSON.toJSONString(tradePayModel));
            AlipayTradePayResponse alipayTradePayResponse = tradePay(tradePayModel);
            log.info("alipayTradePayResponse------>"+alipayTradePayResponse);
            if(alipayTradePayResponse.isSuccess()) {
                //更新账单
                orderBillInfoService.updateById(orderBillInfo);
                tradeOrderSettle(orderBillInfo.getOrderId(), alipayTradePayResponse, dayPaidInAmount);
            }
        } catch (AlipayApiException e) {
            throw new RuntimeException(e.getMessage());
        }
    }
    @Transactional
    public AlipayTradePayResponse tradePay(AlipayTradePayModel alipayTradePayModel) throws AlipayApiException {
        AlipayTradePayInfo tradePayInfo=new AlipayTradePayInfo();
        BeanUtil.copyProperties(alipayTradePayModel,tradePayInfo);

        log.info("tradePay------>" + JSON.toJSONString(alipayTradePayModel));
        //还款计划最后一天和逾期账单，每天发起一次扣除所欠全部欠款，直到扣款成功或者账单结束
        //保存交易信息
        AlipayTradePayResponse alipayTradePayResponse = alipayAuthTradeService.tradePay(defaultAlipayClient, alipayTradePayModel);
        log.info("alipayTradePayResponse-------->" + JSON.toJSONString(alipayTradePayResponse));
        if (alipayTradePayResponse.isSuccess()){
            tradePayInfo.setStatus(TradePayStatusEnum.TRADE_SUCCESS.getCode());
            alipayTradePayInfoService.save(tradePayInfo);
        }else {
            tradePayInfo.setRemarks(alipayTradePayResponse.getMsg());
            tradePayInfo.setStatus(TradePayStatusEnum.TRADE_FAILURE.getCode());
            alipayTradePayInfoService.save(tradePayInfo);
        }
        return alipayTradePayResponse;
    }
    @Transactional
    public OrderFlowInfo saveFlowInfoLog(Long orderId, OrderFlowTypeEnum orderFlowTypeEnum, BigDecimal amount){
        OrderFlowInfo orderFlowInfo =   new OrderFlowInfo();
        orderFlowInfo.setFlowNo(CodeUtils.getFlowNo(orderFlowTypeEnum));
        orderFlowInfo.setAmount(amount);
        orderFlowInfo.setOrderid(orderId);
        orderFlowInfo.setType(orderFlowTypeEnum.getCode());
        orderFlowInfo.setItemName(orderFlowTypeEnum.getMsg());
        orderFlowInfo.setSourceAppId(0);
        orderFlowInfoMapper.insert(orderFlowInfo);
        return orderFlowInfo;
    }
    @Transactional
    public void tradeOrderSettle(Long orderId, AlipayTradePayResponse alipayTradePayResponse, BigDecimal dayPaidInAmount) throws AlipayApiException {
        //1、进行代扣交易
        //2、保存交易信息
        //3、发起分账
        //4、保存分账信息
        AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
        model.setTradeNo(alipayTradePayResponse.getTradeNo());
        List<OpenApiRoyaltyDetailInfoPojo> royaltyParameters = new ArrayList<>();
        //平台服务费分账信息
        OpenApiRoyaltyDetailInfoPojo royaltyInfo = new OpenApiRoyaltyDetailInfoPojo();
        //计算平台服务费
        String platformHandlingFeeRatio = configApi.get("sys_config", "PlatformHandlingFeeRatio");
        double amount =  dayPaidInAmount.multiply(new BigDecimal(platformHandlingFeeRatio)).setScale(2, RoundingMode.HALF_DOWN).doubleValue();
        double commissionAmount =  0D;


        //结算平台手续费
        royaltyInfo.setAmount(Double.toString(amount));
        String platformHandlingName = configApi.get("sys_config","PlatformHandlingName", "平台服务费")  ;
        String platformHandlingDec  =  configApi.get("sys_config","PlatformHandlingDoc", "如通收取平台服务费")  ;
        royaltyInfo.setRoyaltyScene(platformHandlingName);
        royaltyInfo.setDesc(platformHandlingDec);
        //支出账号信息
//        royaltyInfo.setTransOutType(TransInType.USER_ID.getCode());
//        royaltyInfo.setTransOut(outAccountInfo.getAccount());

        //收账方账户信息
        AlipayRoyaltyAccountInfo accountInfo = alipayRoyaltyAccountInfoService.getSysAccountByOrganizationType();
        royaltyInfo.setTransInType(TransInType.USER_ID.getCode());
        //royaltyInfo.setTransInName(accountInfo.getLoginName());
        royaltyInfo.setTransIn(accountInfo.getAccount());
        royaltyInfo.setDesc("如通平台服务费");
        royaltyParameters.add(royaltyInfo);
        //租金15% 暂收至如通 后续进行详细结算  需判断该订单是否由线索转化而来 (目前根据线索当前所处部门 与 订单产生部门进行对比)
        OrderInfo orderInfo = iOrderInfoService.getOrderInfoById(orderId);
        UserVo userVo = iUserService.detail(orderInfo.getUserId());
        Long count = orderClueMapper.selectCount(new LambdaQueryWrapper<OrderClue>()
                .eq(OrderClue::getPhoneNumber,userVo.getMobile())
                .eq(OrderClue::getDeptCode,orderInfo.getDeptCode()));
        if(count>0) {
            String commissionRatio = configApi.get("sys_config", "CommissionRatio");
            String commissionName = configApi.get("sys_config", "CommissionName");
            commissionAmount = dayPaidInAmount.multiply(new BigDecimal(commissionRatio)).setScale(2, RoundingMode.HALF_DOWN).doubleValue();
            OpenApiRoyaltyDetailInfoPojo royaltyInfoRt = new OpenApiRoyaltyDetailInfoPojo();
            royaltyInfoRt.setAmount(Double.toString(commissionAmount));
            //royaltyInfoRt.setTransInName(accountInfo.getLoginName());
            royaltyInfoRt.setTransIn(accountInfo.getAccount());
            royaltyInfoRt.setRoyaltyScene(commissionName);
            royaltyInfoRt.setDesc(commissionName);
            royaltyParameters.add(royaltyInfoRt);
        }
        model.setRoyaltyParameters(royaltyParameters);
        //生成结算流水
        OrderFlowInfo orderFlowInfo = saveFlowInfoLog(orderId,OrderFlowTypeEnum.TRADE_ORDER_SETTLE, new BigDecimal(amount).add(new BigDecimal(commissionAmount)));
        model.setOutRequestNo(orderFlowInfo.getFlowNo());
        //保存分账账单信息
        AlipayTradeOrderSettle tradeOrderSettle = new AlipayTradeOrderSettle();
        BeanUtil.copyProperties(model, tradeOrderSettle);
        log.info("tradeOrderSettle 方法参数------->" + JSON.toJSONString(model));
        AlipayTradeOrderSettleResponse alipayTradeOrderSettleResponse = divideAccountService.tradeOrderSettle(defaultAlipayClient, model);
        log.info("alipayTradeOrderSettleResponse 返回结果------->" + JSON.toJSONString(alipayTradeOrderSettleResponse));
        if (alipayTradeOrderSettleResponse.isSuccess()) {
            //分账成功
            //更细分账信息
            tradeOrderSettle.setStatus(OrderSettleStatusEnum.DISTRIBUTED_SUCCESS.getCode());
        } else {
            tradeOrderSettle.setStatus(OrderSettleStatusEnum.DISTRIBUTED_FAIL.getCode());
        }
        alipayTradeOrderSettleService.save(tradeOrderSettle);
        model.getRoyaltyParameters()
                .forEach(openApiRoyaltyDetailInfoPojo -> {
                    //保存分账方信息（商户信息、分账比例）
                    AlipayTradeOrderRoyaltyDetailInfo alipayTradeOrderRoyaltyDetailInfo = new AlipayTradeOrderRoyaltyDetailInfo();
                    BeanUtil.copyProperties(openApiRoyaltyDetailInfoPojo, alipayTradeOrderRoyaltyDetailInfo);
                    alipayTradeOrderRoyaltyDetailInfo.setAmount(new BigDecimal(openApiRoyaltyDetailInfoPojo.getAmount()));
                    alipayTradeOrderRoyaltyDetailInfo.setSettleDesc(openApiRoyaltyDetailInfoPojo.getDesc());
                    alipayTradeOrderRoyaltyDetailInfoService.save(alipayTradeOrderRoyaltyDetailInfo);
                });
    }

    /**
     * 执行结算扣款
     * @param orderBillInfo 账单信息
     * @return AlipayTradePayResponse
     * @throws AlipayApiException
     */
    @Transactional
    @Override
    public AlipayTradePayResponse execOtherOrderBill(OrderBillInfo orderBillInfo) throws AlipayApiException {
        AlipayTradePayResponse alipayTradePayResponse = tradePay(createAlipayTradePay(orderBillInfo, orderBillInfo.getTotalReceivables()));
        if (alipayTradePayResponse.isSuccess()){
            saveFlowInfoLog(orderBillInfo.getOrderId(),OrderFlowTypeEnum.TRADE_ORDER_SETTLE,orderBillInfo.getTotalReceivables());
        }
        return alipayTradePayResponse;
    }

    @Transactional
    @Override
    public AlipayTradePayModel createAlipayTradePay(OrderBillInfo orderBillInfo,BigDecimal dayPaidInAmount) {
        AlipayTradePayModel tradePayModel = new AlipayTradePayModel();
        AlipaySignUserAgreementRecord agreementRecord = alipaySignUserAgreementRecordService.getRecordByUserId(orderBillInfo.getUserId());
        Assert.notNull(agreementRecord,"该用户签约记录不存在");
        AgreementParams agreementParams = new AgreementParams();
        agreementParams.setAgreementNo(agreementRecord.getAgreementNo());
        //代扣信息。 代扣业务需要传入的协议相关信息，使用本参数传入协议号后scene和auth_code不需要再传值。
        tradePayModel.setAgreementParams(agreementParams);
        //商户订单号
        tradePayModel.setOutTradeNo(OrderNoUtils.getOrderUUID("otn" + orderBillInfo.getOrderId().toString()));
        tradePayModel.setTotalAmount(dayPaidInAmount.toString());
        AlipayRoyaltyAccountInfo seller = alipayRoyaltyAccountInfoService.getSysAccountByOrganizationType();
        //支出方账户信息
        AlipayRoyaltyAccountInfo outAccountInfo = alipayRoyaltyAccountInfoService.getAccountByMerchantId(orderBillInfo.getMerchantId());
        if(Objects.isNull(outAccountInfo)){
            outAccountInfo = alipayRoyaltyAccountInfoService.getAccountByMerchantId(1L);
        }
        //设置订单名称
        tradePayModel.setSubject(orderBillInfo.getName());
        tradePayModel.setProductCode("GENERAL_WITHHOLDING");
        //设置卖家编号
        tradePayModel.setSellerId(seller.getAccount());

        //二级商户 default_settle_rule
        SubMerchant subMerchant = new SubMerchant();
        subMerchant.setMerchantId(outAccountInfo.getAccount());
        tradePayModel.setSubMerchant(subMerchant);
        tradePayModel.setOutTradeNo(OrderNoUtils.getOrderUUID("otn" + orderBillInfo.getOrderId().toString()));
        //结算信息
        SettleInfo settleInfo = new SettleInfo();
        SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
        settleDetailInfo.setAmount(tradePayModel.getTotalAmount());
        settleDetailInfo.setTransInType("defaultSettle");
        List<SettleDetailInfo> settleDetailInfoList = new ArrayList<>();
        settleDetailInfoList.add(settleDetailInfo);
        settleInfo.setSettleDetailInfos(settleDetailInfoList);
        tradePayModel.setSettleInfo(settleInfo);
        return tradePayModel;
    }
    @Transactional
    @Override
    public void auditBill(AuditOrderBillValidate auditOrderBillValidate) throws AlipayApiException {
        OrderBillInfo orderBillInfo = orderBillInfoService.getById(auditOrderBillValidate.getId());
        Assert.notNull(orderBillInfo,"该账单不存在");
        orderBillInfo.setStatus(auditOrderBillValidate.getStatus());
        orderBillInfo.setRemark(auditOrderBillValidate.getRemark());
        if (null!=auditOrderBillValidate.getStatus()&&auditOrderBillValidate.getStatus().equals(LeaseOrderStatusEnum.TO_BE_PAID.getCode())||
                null!=auditOrderBillValidate.getStatus()&&auditOrderBillValidate.getStatus().equals(LeaseOrderStatusEnum.REJECTED_FOR_MODIFICATION.getCode())) {
            orderBillInfoService.updateById(orderBillInfo);
        }
        if (null!=auditOrderBillValidate.getStatus()&&auditOrderBillValidate.getStatus().equals(LeaseOrderStatusEnum.TO_BE_PAID.getCode())){
            //执行账单费用扣除
            execOtherOrderBill(orderBillInfo);
        }
    }
    @Transactional
    @Override
    public void addPenaltyBill(OrderBillInfoValidate orderBillInfoValidate) {
        Assert.notNull(orderBillInfoValidate.getType(),"账单类型不能为空");
        if (!orderBillInfoValidate.getType().equals(4)&&!orderBillInfoValidate.getType().equals(5)){
             throw new IllegalArgumentException("账单类型不正确");
        }
        OrderInfo orderInfo = iOrderInfoService.getOrderInfoById(orderBillInfoValidate.getOrderId());
        Assert.notNull(orderInfo,"订单不存在");
        Assert.isTrue(iSystemAuthDeptService.isExist(orderInfo.getDeptId()),"商户不存在");
        Assert.isTrue(iUserService.isExist(orderInfo.getUserId()),"用户不存在");
        orderBillInfoService.createBillInfo(orderBillInfoValidate.getOrderId()
                ,orderInfo.getDeptId(),
                orderInfo.getUserId(),orderBillInfoValidate.getTotalReceivables(),
                orderBillInfoValidate.getName(), LeaseOrderStatusEnum.IN_REVIEW.getCode(),orderBillInfoValidate.getType());
    }

}
